﻿//【进阶】42.异常
//【头文件包含】
//C++的主要头文件
#include<iostream>//c++的输入输出流
using namespace std;
#include<algorithm>
#include<string>
#include<vector>
#include<list>
//C的主要头文件
//#include<stdio.h>
//#include<stdlib.h>
//#include<assert.h>
//#include<string.h> 
#include <thread>
#include <mutex>
#include <atomic>

//【命名空间】

//【类声明】
//定义一个异常基类
class Exception
{
protected:
	string _errmsg;
	int _id;
	//list<StackInfo> _traceStack;
	// ...
};
class SqlException : public Exception
{
};
class CacheException : public Exception
{
};
class HttpServerException : public Exception
{
};



//【函数声明】
void Test1();void Test2();void Test3();void Test4();

//【主函数】
int main()
{
	cout << "****主函数开始****" << endl;
	try{
		Test1();
		Test2();
		Test3();
		Test4();
	}
	catch (...) //在主程序最外层设置一个接收任意异常的结构可以保证在栈展开最终捕获到异常
	{
		cout << "unkown exception" << endl;
	}
	cout << "****主函数结束****" << endl;
	return 0;
}

//【函数定义】

/*测试用例*/void Test1()
{
	cout << "****测试用例开始****"<< endl;
	try 
	{
		vector<int> v1 = {1,2,3,4,5,6};
		for (int i = 0;i <= v1.size();++i)
		{
			if (i == v1.size())
			{
				throw - 1;//利用throw抛出异常状态，再由一个对应catch接收异常
			}
			//cout << v1[i] << " ";
			cout << v1.at(i) << " ";
		}
		cout << endl;
	}//一个try块后面可以接多个catch用于接收不同情况的异常
	catch (exception& e)
	{
		cout << endl;
		cout << e.what() << endl;
	}
	catch (int err)
	{
		cout << endl;
		cout <<"发生越界访问错误：" << err << endl;
	}
	cout << "****测试用例结束****" << endl << endl;
}

/*测试用例*/void Test2()
{
	cout << "****测试用例开始****" << endl;
	try {
		// server.Start();
		// 抛出对象都是派生类对象
	}
	catch (const Exception& e) // 这里捕获父类对象就可以
	{

	}
	catch (...)
	{
		cout << "Unkown Exception" << endl;
	}
	cout << "****测试用例结束****" << endl<<endl;
}

/*测试用例*/void Test3()
{
	cout << "****测试用例开始****" << endl;
	
	cout << "****测试用例结束****" << endl << endl;
}

/*测试用例*/void Test4()
{
	cout << "****测试用例开始****" << endl;
	
	cout << "****测试用例结束****" << endl << endl;
}




//【笔记】
//【进阶】42.异常
	// 异常是面向对象语法处理错误的方式
	// C语言中处理错误采用1.返回错误码 2.终止程序
	// C语言处理错误的方式存在缺陷：
		// 1. 面对部分函数无法处理，如通过返回值拿数据，发生错误难处理
		// 2. 如果调用函数栈很深，逐层返回错误码不便于查错
		// 3. 错误码需要查询错误码表来确认是什么错误 
	// C++ 通过使用异常来解决以上缺陷 
	// 异常的匹配原则
		// 1. 异常是通过抛出对象而引发的，对象类型决定激活哪个catch的处理代码。
		// 2. 被选中的处理代码是调用链中与该对象【类型匹配】且【离抛出异常位置最近】的那一个。
		// 3. 抛出异常对象时，抛出对象可能是临时对象，所以会生成一个拷贝对象，拷贝对象会在被catch以后销毁。（处理类似于函数传值返回）
		// 4. catch (...)可以捕获任意类型的异常，但不知道异常错误是什么。
		// 5. 抛出和捕获的匹配原则有例外，并不都是类型完全匹配，可以抛出的派生类对象，使用基类捕获，在实际中非常实用，后面会学到
	// 异常的重新抛出
		// 异常发生前如果出现动态开辟的内存空间等操作，那么如果抛异常时要先进行资源释放再重新抛出异常进行处理
	// 自定义异常体系
		// 在复杂工程中，定义一个自定义异常基类包含错误码、错误id、调用栈帧等成员
		// 后续的自定义异常集成该基类，最终由基类进行捕获异常
	//异常规范
		// 1. 异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。 可以在函数的后面接throw(类型)，列出这个函数可能抛掷的所有异常类型。
		// 2. 函数的后面接throw()或noexcept，表示函数不抛异常。
		// 3. 若无异常接口声明，则此函数可以抛掷任何类型的异常。
		// 4. 构造和析构函数不要抛异常
		// 5. 在luck和unlock之间抛异常会导致死锁
		// 6. 要结合智能指针的RAII解决异常安全问题
	//异常的优缺点：整体而言利大于弊
		//优点：1. 清晰包含错误信息；2. 面对operator[]这种函数越界异常可以更好解决；3. 深层错误，可以直接最外层捕获
		//缺点：1. 导致执行流混乱不利于调试；2. 异常导致资源泄漏带来的异常安全问题；3. C++语法能抛任意异常，需要规范管理
//
//
//
//
//
// 
// 
// 
// 



		









